package com.zhixing.common.handler;

import com.fasterxml.jackson.databind.exc.InvalidFormatException;
import com.zhixing.common.domain.enums.HttpStatus;
import com.zhixing.common.exception.ZhixingException;
import com.zhixing.common.utils.Res;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.servlet.resource.NoResourceFoundException;

import java.util.List;

@Slf4j
@RestControllerAdvice
@ConditionalOnClass(DispatcherServlet.class)
public class GlobalExceptionHandler {

    @ExceptionHandler(ZhixingException.class)
    public Res<Void> error(ZhixingException e) {
        log.error("业务异常捕获：{}", e.getHttpStatus().getMsg());
        return Res.error(e.getHttpStatus());
    }

    @ExceptionHandler(MethodArgumentNotValidException.class)
    public Res<Void> error(MethodArgumentNotValidException e) {
        log.error("方法参数无效异常捕获：{}", e.getMessage());
        List<FieldError> fieldErrors = e.getBindingResult().getFieldErrors();
        StringBuilder sb = new StringBuilder();
        for (FieldError fieldError : fieldErrors) {
            sb.append(fieldError.isBindingFailure() ? (fieldError.getField() + "参数格式错误") : fieldError.getDefaultMessage()).append(";");
        }
        return Res.error(HttpStatus.BAD_REQUEST.getCode(), sb.toString());
    }

    @ExceptionHandler(HttpMessageNotReadableException.class)
    public Res<Void> error(HttpMessageNotReadableException e) {
        log.error("Http消息无法读取异常捕获：{}", e.getMessage());
        Throwable cause = e.getCause();
        if (cause instanceof InvalidFormatException) {
            String message = e.getMessage(), msg = "参数格式错误";
            int left = message.indexOf('`'), right = -1;
            if (left != -1) right = message.substring(left + 1).indexOf('`');
            if (right != -1) {
                String[] split = message.substring(left + 1, left + right + 1).split("\\.");
                if (split.length > 0) msg = split[split.length - 1].toLowerCase() + msg;
            }
            return Res.error(HttpStatus.BAD_REQUEST.getCode(), msg);
        }
        return Res.error(HttpStatus.BAD_REQUEST);
    }

    @ExceptionHandler(NoResourceFoundException.class)
    public Res<Void> error(NoResourceFoundException e) {
        log.error("资源未找到异常捕获：{}", e.getMessage());
        return Res.error(HttpStatus.NOT_FOUND);
    }

    @ExceptionHandler(MethodArgumentTypeMismatchException.class)
    public Res<Void> error(MethodArgumentTypeMismatchException e) {
        log.error("方法参数类型异常捕获：{}", e.getMessage());
        return Res.error(HttpStatus.PARAMETER_TYPE_ERROR);
    }

    @ExceptionHandler(MissingServletRequestParameterException.class)
    public Res<Void> error(MissingServletRequestParameterException e) {
        log.error("方法参数缺失异常捕获：{}", e.getMessage());
        return Res.error(HttpStatus.METHOD_PARAMETER_MISSING);
    }

    @ExceptionHandler(Exception.class)
    public Res<Void> error(Exception e) {
        log.error("全局异常捕获：{}", e.getMessage());
        return Res.error(HttpStatus.INTERNAL_SERVER_ERROR);
    }
}
